﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufArrangementAreaContent.h"
#include "GnufINotificationCenterEventHandler.h"

namespace gnuf {
    class QtGraphicsCanvas;
    class Bulletin;
    class IAssetDisplay;
    class DisplayManagerEventArgs;
    class ProjectDisplayEventArgs;
    class AssetDisplayEventArgs;
    class HotkeysChangedEventArgs;
    class Color;
    class IsolatedArrangementAreaContent;
    class TiledShowcase;
    class TiledShowcaseMaintainer;

    class GNUF_BASE_EXPORT GraphicsCanvas final
        : public ArrangementAreaContent
        , public INotificationCenterEventHandler
    {
        DEFINE_CAST_DERIVED(GraphicsCanvas, ArrangementAreaContent)

    public:
        explicit GraphicsCanvas(const std::wstring & key, bool major);
        virtual ~GraphicsCanvas();

        static GraphicsCanvas* get();

        ///\brief Check if this graphics canvas is major.
        /// Return true if major, return false if minor.
        bool isMajor() const { return m_major; }

        ///\brief Assign the background color.
        static void assignBackgroundColor(const Color &);
        ///\brief Return the assigned background color.
        static const Color * assignedBackgroundColor();
        ///\brief Clear the assigned background color;
        static void clearAssignedBackgroundColor();

        static QWidget * ativeQtCanvas();
        
        /// \brief Try to hint at stuffing back the IsolatedArrangementAreaContent.
        static void tryToHintAtStuffingBack(const IsolatedArrangementAreaContent *);
        /// \brief The stuffing-back hint is showing.
        static bool isHintingAtStuffingBack();
        /// \brief Do not want to hint at the stuffing-back, any more.
        static void donotHintAtStuffingBack();

        std::uint64_t windowId() const;

        bool isOkCancelVisible() const;
        void showOkCancelButtons(const std::wstring &);
        void hideOkCancelButtons();

        void activateCanvas();

        enum class EReasonOfTransferring { eOnIsolating, eOffIsolating, eOnTiling, eOffTiling };
        void transferOneTo(GraphicsCanvas *, const IAssetDisplay * const,
                           const GraphicsCanvas::EReasonOfTransferring);
        void transferAllTo(GraphicsCanvas *, const GraphicsCanvas::EReasonOfTransferring);

        IAssetDisplay * assetDisplayById(const std::string &) const;

        void onMouseButtonClickedOn(const QtGraphicsCanvas * const);

        bool makeScreenShot(std::wstring & filePath, const std::string & assetDisplayId = "") const;

        ///\brief Build the grid 2x2 tiled show case.
        bool buildGrid2x2TiledShowcase();
        ///\brief Build the tiled show case.
        ///\return Return false if failed to build.
        bool buildTiledShowcase(gcmp::OwnerPtr< TiledShowcase > &&);
        ///\return Return true if it can build the tiled show case.
        bool canBuildTiledShowcase() const;
        ///\brief Quit the tiled show case.
        void quitTiledShowcase();
        ///\brief Return true if in the tiled showcase. Otherwise, return false.
        bool  isInTiledShowcase() const;
        ///\brief Return the tile index.
        ///For Grid2x2Tiled, the index.first is 0:Above or 1:Below, or 0:Left or 1:Right; the index.second is the tile index.
        ///For FreeTiled, the index.first always is -1; the index.second is the tile index.
        ///\param id: an ID (e.g. the UiView's ID)
        std::pair<int, int> tileIndexOf(const std::string & id) const;
        std::pair<int, int> tileIndexOf(const IAssetDisplay *) const;

        void cleanTiledShowcase() { quitTiledShowcase(); } // for Downward Compatibility

        ///\return Return the asset display.
        const IAssetDisplay * assetDisplay() const;
        ///\return Return true if there is the asset display.
        bool hasAssetDisplay(const IAssetDisplay *) const;
        ///\return Return all the asset displays.
        using Stack = std::list< IAssetDisplay * >;
        const GraphicsCanvas::Stack & assetDisplays() const { return m_stack; }

        void setBorder(int left, int top, int right, int bottom);

        void handleEvent(const ProjectDisplayEventArgs &);

    protected:
        // Inherits from ArrangementAreaContent...
        virtual QWidget * qtWidget() override;
        virtual void onPostVisibilityChanged() override;
        virtual void onPostConnectedWithArrangementArea() override;
        virtual void onPostReconnectedWithArrangementArea() override;
        virtual void onPreDisconnectedFromArrangementArea() override;
        virtual void onPostGeometryChanged() override;
        virtual bool onDoesAcceptDrop(DragMove*) const override;
        virtual void onDrop(DragMove*) override;
        virtual gcmp::OwnerPtr<ArrangementAreaContent>
            clone() const override;
        virtual void onEvent(ArrangementAreaEvent *) override;

        // Inherits from INotificationCenterEventHandler...
        virtual void onEvent(INotificationCenterEventArgs *) override;
    private:
        void handleEvent(DisplayManagerEventArgs *);
        void handleEvent(ProjectDisplayEventArgs *);
        void handleEvent(AssetDisplayEventArgs *);
        void handleEvent(HotkeysChangedEventArgs *);

        bool buildTiledShowcase(gcmp::OwnerPtr< TiledShowcase > &&, const bool);
        void setAssetDisplay(IAssetDisplay *);

        const bool m_major;
        GraphicsCanvas::Stack m_stack;
        gcmp::WeakPtr< IAssetDisplay > m_wpAssetDisplay;
        gcmp::OwnerPtr< QtGraphicsCanvas > m_qtGraphicsCanvas;
        gcmp::OwnerPtr< TiledShowcaseMaintainer > m_opTiledShowcaseMaintainer;
    };
    
}